/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       string.h
 * Author:     karooolek
 * Created on: 2008-12-30
 *
 **********************************************************************************************************************/

#ifndef STRING_H_
#define STRING_H_

#include "types.h"
#include <cstring>
#include <string>
#include <sstream>

/**
 * Stringize (change into string) argument.
 * @param X argument to stringize.
 */
#define _STRINGIZE(X) #X
#define STRINGIZE(X) _STRINGIZE(X)

namespace mGameEngine
{

/**
 * String object.
 * String works fine with both C-strings and std::strings.
 * It uses standard 8-bit characters.
 * Provides construction, assignment and concatenation with any
 * type with lexical representation.
 */
class String : public std::string
{
public:
    /**
     * Create empty string.
     */
    String() : std::string()
    {
    }

    /**
     * C-string constructor.
     * @param str C-string to copy
     */
    String(const char *str) : std::string(str)
    {
    }

    /**
     * std::string constructor.
     * @param str std::string to copy
     */
    String(const std::string &str) : std::string(str)
    {
    }

    /**
     * Copy constructor.
     * @param str string to copy
     */
    String(const String &str) : std::string(str.c_str())
    {
    }

    /**
     * Create string from lexical representation of any value.
     * @param val value
     */
    template<typename TVal>
    String(const TVal &val) : std::string()
    {
        *this = val;
    }

    /**
     * Assign C-string.
     * @param str C-string to assign
     * @return string with new value
     */
    String &operator=(const char *str)
    {
        assign(str);
        return *this;
    }

    /**
     * Assign std::string.
     * @param str std::string to assign
     * @return String with new value
     */
    String &operator=(const std::string &str)
    {
        assign(str);
        return *this;
    }

    /**
     * Assign String.
     * @param str string to assign
     * @return String with new value
     */
    String &operator=(const String &str)
    {
        assign(str.c_str());
        return *this;
    }

    /**
     * Assign lexical representation of any value.
     * @param val value
     * @return String with assigned value
     */
    template<typename TVal>
    String &operator=(const TVal &val)
    {
        std::ostringstream oss;
        oss << val;
        assign(oss.str());

        return *this;
    }

    /**
     * Concatenate String with C-string.
     * @param str C-string to concatenate
     * @return concatenaded String and C-string
     */
    String operator+(const char *str) const
    {
        String tmp(*this);
        tmp.append(str);
        return tmp;
    }

    /**
     * Concatenate C-string and String
     * @param str1 C-string to concatenate
     * @param str2 String to concatenate
     * @return concatenated C-string and String
     */
    friend String operator+(const char *str1, const String &str2)
    {
        return String(str1) + str2;
    }

    /**
     * Concatenate String with std::string.
     * @param str std::string to concatenate
     * @return concatenated String and std::string
     */
    String operator+(const std::string &str) const
    {
        String tmp(*this);
        tmp.append(str);
        return tmp;
    }

    /**
     * Concatenate std::string and String
     * @param str1 std::string to concatenate
     * @param str2 String to concatenate
     * @return concatenated std::string and String
     */
    friend String operator+(const std::string &str1, const String &str2)
    {
        return String(str1) + str2;
    }


    /**
     * Concatenate String with lexical representation of any value.
     * @param val value to concatenate
     * @return concatenated String and value
     */
    template<typename T>
    String operator+(const T &val)
    {
        std::ostringstream oss;
        oss << *this << val;
        return String(oss.str());
    }

    /**
     * Concatenate lexical representation of any value with String.
     * @param val value to concatenate
     * @param str String to concatenate
     * @return concatenated value and String
     */
    template<typename T>
    friend String operator+(const T &val, const String &str)
    {
        std::ostringstream oss;
        oss << val << str;
        return String(oss.str());
    }

    /**
     * C-string cast.
     * @return C-string
     */
    operator const char *() const
    {
        return c_str();
    }

    /**
     * Any type lexical cast.
     * @return value represented by string
     */
    template<typename TVal>
    operator TVal() const
    {
        std::istringstream iss(*this);
        TVal tmp;
        iss >> tmp;
        return tmp;
    }

};

}

#endif // STRING_H_
